package cn.jx.cjm.payment.wechat.v2.support;

import cn.jx.cjm.common.enums.BizExceptionEnum;
import cn.jx.cjm.common.enums.GlobalExceptionEnum;
import cn.jx.cjm.common.exception.BizException;
import cn.jx.cjm.common.util.HttpClientUtils;
import cn.jx.cjm.payment.wechat.v2.config.WechatPayProperties;
import cn.jx.cjm.payment.wechat.v2.dto.request.PayRequest;
import cn.jx.cjm.payment.wechat.v2.dto.request.RefundRequest;
import cn.jx.cjm.payment.wechat.v2.dto.request.WechatPayRequest;
import cn.jx.cjm.payment.wechat.v2.dto.request.WechatRefundRequest;
import cn.jx.cjm.payment.wechat.v2.dto.response.WechatPayResponse;
import cn.jx.cjm.payment.wechat.v2.dto.response.WechatRefundNotifyResponse;
import cn.jx.cjm.payment.wechat.v2.dto.response.WechatUserInfoResponse;
import cn.jx.cjm.payment.wechat.v2.dto.response.WechatUserJudgeResponse;
import cn.jx.cjm.payment.wechat.v2.enums.AppTypeEnum;
import cn.jx.cjm.payment.wechat.v2.enums.PaymentWayEnum;
import cn.jx.cjm.payment.wechat.v2.sdk.WXPay;
import cn.jx.cjm.payment.wechat.v2.sdk.WXPaySdkConfig;
import cn.jx.cjm.payment.wechat.v2.sdk.WXPayUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @author James Chen right_way@foxmail.com
 * @version 1.0
 * <p>
 *
 * </p>
 * @since 2020/11/1 15:15
 */
@Component
@Slf4j
public class WechatPaySupportService {

    @Autowired
    private WechatPayProperties wechatPayProperties;

    /**
     * 获取用户OPENID
     *
     * @param code
     * @param payType
     * @param appName
     * @return
     */
    public WechatUserJudgeResponse getOpenid(String code, Integer payType, String appName) {
        String url = AppTypeEnum.getUrl(payType, wechatPayProperties.getAppId(), getAppSecret(appName), code);
        String result = HttpClientUtils.getRequest(url);
        log.info("获取openid url：{}, result:{}", url, result);
        return JSON.parseObject(result, WechatUserJudgeResponse.class);
    }


    /**
     * 获取用户信息
     *
     * @param appType     应用类型
     * @param accessToken accessToken
     * @param openid      openID
     * @return .
     */
    public WechatUserInfoResponse getWechatUserInfo(Integer appType, String accessToken, String openid) {
        String url = AppTypeEnum.getUserInfoUrl(appType, accessToken, openid);
        String result = HttpClientUtils.getRequest(url);
        log.info("获取openid url：{}, result:{}", url, result);
        return JSON.parseObject(result, WechatUserInfoResponse.class);

    }

    /**
     * 统一支付订单
     *
     * @param payRequest
     * @param paymentWayEnum
     * @return
     */
    public WechatPayResponse pay(PayRequest payRequest, PaymentWayEnum paymentWayEnum) {
        WechatPayRequest wechatPayRequest = new WechatPayRequest();
        BeanUtils.copyProperties(payRequest, wechatPayRequest);

        wechatPayRequest.setAppid(wechatPayProperties.getAppId());
        wechatPayRequest.setTrade_type(paymentWayEnum.getType());
        wechatPayRequest.setNotify_url(wechatPayProperties.getNotifyUrl());

        WXPaySdkConfig wxPaySdkConfig = new WXPaySdkConfig(wechatPayProperties);
        try {
            WXPay wxPay = new WXPay(wxPaySdkConfig);
            Map<String, String> responseMap = wxPay.unifiedOrder(wechatPayRequest.toMap());
            WechatPayResponse wechatPayResponse = com.baomidou.mybatisplus.core.toolkit.BeanUtils.mapToBean(responseMap, WechatPayResponse.class);
            if (!wechatPayResponse.getResult_code().equals("SUCCESS")) {
                log.error("调用微信SDK创建微信预支付订单出现异常,{}", wechatPayResponse);
                throw new BizException(BizExceptionEnum.WXPREPAYERROR.getCode(), wechatPayResponse.getReturn_msg());
            }
            return wechatPayResponse;
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("调用微信SDK创建微信预支付订单出现异常,prePayOrderNo:{}", wechatPayRequest.getOut_trade_no());
            throw new BizException(GlobalExceptionEnum.SERVER_ERROR);
        }
    }


    /**
     * 退款
     *
     * @param refundRequest
     * @return
     */
    public WechatRefundNotifyResponse refund(RefundRequest refundRequest) {
        WechatRefundRequest wechatRefundRequest = new WechatRefundRequest();
        BeanUtils.copyProperties(refundRequest, wechatRefundRequest);
        wechatRefundRequest.setAppid(wechatPayProperties.getAppId());
        wechatRefundRequest.setNotify_url(wechatPayProperties.getRefundNotifyUrl());

        WXPaySdkConfig wxPaySdkConfig = new WXPaySdkConfig(wechatPayProperties);
        try {
            WXPay wxPay = new WXPay(wxPaySdkConfig);
            Map<String, String> responseMap = wxPay.refund(wechatRefundRequest.toMap());
            WechatRefundNotifyResponse wechatRefundNotifyResponse = com.baomidou.mybatisplus.core.toolkit.BeanUtils.mapToBean(responseMap, WechatRefundNotifyResponse.class);

            if (!wechatRefundNotifyResponse.getResult_code().equals("SUCCESS")) {
                log.error("调用微信支付生成退款订单出现异常,{}", wechatRefundNotifyResponse);
                throw new BizException(BizExceptionEnum.WXPREPAYERROR.getCode(), wechatRefundNotifyResponse.getReturn_msg());
            }
            return wechatRefundNotifyResponse;
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("调用微信SDK创建微信退款订单出现异常,prePayOrderNo:{}", refundRequest.getOut_refund_no());
            throw new BizException(GlobalExceptionEnum.SERVER_ERROR);
        }

    }

    /**
     * @param appName
     * @return
     */
    private String getAppSecret(String appName) {
        if (!StringUtils.isEmpty(appName)) {
            return wechatPayProperties.getMiniApps().get(appName);
        } else {
            return wechatPayProperties.getSecret();
        }
    }

    /**
     * 获取request中xml
     * @param inputStream
     * @return
     * @throws IOException
     */
    public String readStreamString(InputStream inputStream) throws IOException {
        try (
                InputStreamReader input = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
                BufferedReader bufferedReader = new BufferedReader(input)
        ) {
            StringBuilder xml = new StringBuilder();
            String line = bufferedReader.readLine();
            while (line != null) {
                xml.append(line);
                line = bufferedReader.readLine();
            }
            return xml.toString();
        }
    }


    /**
     * 签名验证
     * @param xmlString
     * @return
     */
    public boolean checkSign(String xmlString) {
        WXPaySdkConfig wxPaySdkConfig = new WXPaySdkConfig(wechatPayProperties);
        try {
            Map<String, String> notifyMap = WXPayUtil.xmlToMap(xmlString);
            WXPay wxpay = new WXPay(wxPaySdkConfig);
            if (!wxpay.isPayResultNotifySignatureValid(notifyMap)) {
                log.error("微信回调参数签名不正确: {}", xmlString);
                return  false;
            }
            log.info("微信回调参数签名验证成功: {}", xmlString);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("微信回调参数失败: {}", xmlString);
            return false;
        }
    }

}
